package com.itheima.utils;

import com.sun.deploy.util.StringUtils;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;

import java.io.InputStream;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;

public class SqlSessionFactoryBuilder {

    public SessionFactory build(InputStream inputStream) throws Exception {

        Configuration configuration = new Configuration();
        Document document = new SAXReader().read(inputStream);
        Element rootElement = document.getRootElement();
        List<Element> nodes = rootElement.selectNodes("//property");
        for (Element element : nodes) {
            String name = element.attributeValue("name");
            String value = element.attributeValue("value");
            if ("driver".equals(name)) {
                configuration.setDriver(value);
            }
            if ("url".equals(name)) {
                configuration.setUrl(value);
            }
            if ("username".equals(name)) {
                configuration.setUsername(value);
            }
            if ("password".equals(name)) {
                configuration.setPassword(value);
            }
        }

        List<Element> list = rootElement.selectNodes("//mapper");
        for (Element element : list) {

            String resource = element.attributeValue("resource");
            String className = element.attributeValue("class");

            if (resource!=null && !"".equals(resource)){
                parseMapper(configuration, resource);
            }
            if (className!=null && !"".equals(className)){
                parseMapperClass(configuration, className);
            }
        }

        return new DefaultSessionFactory(configuration);
    }

    private void parseMapperClass(Configuration configuration, String className) throws Exception {

        Class<?> clazz = Class.forName(className);
        Method[] declaredMethods = clazz.getDeclaredMethods();
        for (Method method : declaredMethods) {
            String methodName = method.getName();
            Select select = method.getAnnotation(Select.class);
            if (select!=null) {
                String sql = select.value();
                Type genericReturnType = method.getGenericReturnType();
                if (genericReturnType instanceof ParameterizedType) {
                    ParameterizedType parameterizedType = (ParameterizedType) genericReturnType;
                    Type type = parameterizedType.getActualTypeArguments()[0];
                    configuration.getMappers().put(className+"."+methodName, new Mapper(sql, type.getTypeName()));
                } else if(genericReturnType instanceof Type) {
                    configuration.getMappers().put(className+"."+methodName, new Mapper(sql, genericReturnType.getTypeName()));
                }
            }
            Insert insert = method.getAnnotation(Insert.class);
            if (insert!=null) {
                String sql = insert.value();
                configuration.getMappers().put(className+"."+methodName, new Mapper(sql, null));
            }
            Update update = method.getAnnotation(Update.class);
            if (update!=null) {
                String sql = update.value();
                configuration.getMappers().put(className+"."+methodName, new Mapper(sql, null));
            }
        }
    }

    private void parseMapper(Configuration configuration, String resource) throws Exception {

        InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream(resource);
        Document document = new SAXReader().read(inputStream);
        Element rootElement = document.getRootElement();
        String namespace = rootElement.attributeValue("namespace");
        List<Element> selects = rootElement.selectNodes("//select");
        for (Element select : selects) {
            String id = select.attributeValue("id");
            String sql = select.getText();
            String resultType = select.attributeValue("resultType");
            Mapper mapper = new Mapper(sql, resultType);
            configuration.getMappers().put(namespace+"."+id, mapper);
        }


    }



}
